package pkt

import (
	"encoding/binary"
	"sdk/sdktype"
	// "fmt"
)

type UcTlv struct {
	Type uint16
	Len  uint16
}

func (v *UcTlv) PackLen() int {
	return 4
}

func (v *UcTlv) Pack(buf []byte) int {
	index := 0
	binary.BigEndian.PutUint16(buf[index:], v.Type)
	index += 2
	binary.BigEndian.PutUint16(buf[index:], v.Len)

	return v.PackLen()
}

func (v *UcTlv) UnPack(buf []byte) int {
	index := 0
	v.Type = binary.BigEndian.Uint16(buf[index:])
	index += 2
	v.Len = binary.BigEndian.Uint16(buf[index:])

	return v.PackLen()
}

const (
	NET_HEADER_LEN    = 12
	NET_HEADER_V2_LEN = 24
	UCPH_DHR_SIZE_LEN = 16
)

//网络头部
type Net_Header_t struct {
	Encrypt   uint8
	Compress  uint8
	Hlen      uint8
	Ver       uint8
	Ds_type   uint8
	Command   uint16
	Param_len uint32
	Handle    uint32
}

func (v *Net_Header_t) PackLen() int {
	return NET_HEADER_LEN
}

func (v *Net_Header_t) Pack(buf []byte) int {
	index := 0
	var flag byte = 0
	flag |= (v.Ver & 0x07) << 5
	flag |= (v.Hlen & 0x07) << 2
	flag |= (v.Compress & 0x01) << 1
	flag |= v.Encrypt & 0x01

	buf[0] = flag
	buf[1] = v.Ds_type
	index += 2
	binary.BigEndian.PutUint16(buf[index:], v.Command)
	index += 2
	binary.BigEndian.PutUint32(buf[index:], v.Param_len)
	index += 4
	binary.BigEndian.PutUint32(buf[index:], v.Handle)
	index += 4

	return index
}

func (v *Net_Header_t) UnPack(buf []byte) int {
	index := 0
	var flag byte = buf[0]
	v.Ver = (flag >> 5) & 0x07
	v.Hlen = (flag >> 2) & 0x07
	v.Compress = (flag >> 1) & 0x01
	v.Encrypt = flag & 0x01
	v.Ds_type = buf[1]
	index += 2
	v.Command = binary.BigEndian.Uint16(buf[index:])
	index += 2
	v.Param_len = binary.BigEndian.Uint32(buf[index:])
	index += 4
	v.Handle = binary.BigEndian.Uint32(buf[index:])
	index += 4

	return index
}

type Pkt_t struct {
	Total uint32
	Cmd   uint32
	Hlen  uint32
	Data  []byte
}

func Pkt_new(cmd uint32, param_len uint32, ds_type uint8) *Pkt_t {
	var pkt Pkt_t
	var hdr Net_Header_t

	pkt.Total = NET_HEADER_LEN + param_len
	pkt.Cmd = cmd

	hdr.Ver = sdktype.PROTO_VER1
	hdr.Hlen = NET_HEADER_LEN / 4
	hdr.Command = uint16(cmd)
	hdr.Param_len = param_len
	hdr.Ds_type = ds_type
	pkt.Hlen = NET_HEADER_LEN
	pkt.Data = make([]byte, pkt.Total)
	hdr.Pack(pkt.Data[0:])

	return &pkt
}

type Net_Header_V2_t struct {
	Head  Net_Header_t
	Flags uint8
	resv  [3]uint8
	Sn    uint64
}

func (v *Net_Header_V2_t) PackLen() int {
	return NET_HEADER_V2_LEN
}

func (v *Net_Header_V2_t) Pack(buf []byte) int {
	index := 0
	index += v.Head.Pack(buf[index:])
	buf[index] = v.Flags
	index += 4
	binary.BigEndian.PutUint64(buf[index:], v.Sn)
	index += 8

	return index
}

func (v *Net_Header_V2_t) UnPack(buf []byte) int {
	index := 0
	index += v.Head.UnPack(buf[index:])
	v.Flags = buf[index]
	index += 4
	v.Sn = binary.BigEndian.Uint64(buf[index:])
	index += 8

	return index
}

func Pkt_new_v2(cmd uint32, param_len uint32, flags uint8, slave_sn uint64, ds_type uint8) *Pkt_t {
	var pkt Pkt_t
	var hdr Net_Header_V2_t

	pkt.Total = NET_HEADER_V2_LEN + param_len
	pkt.Cmd = cmd

	hdr.Head.Ver = sdktype.PROTO_VER2
	hdr.Head.Hlen = NET_HEADER_V2_LEN / 4
	hdr.Head.Command = uint16(cmd)
	hdr.Head.Param_len = param_len
	hdr.Flags = flags
	hdr.Sn = slave_sn
	pkt.Hlen = NET_HEADER_V2_LEN
	pkt.Data = make([]byte, pkt.Total)
	hdr.Pack(pkt.Data[0:])

	return &pkt
}

//disp结构包
type Ucla_req_disp_hdr_t struct {
	Apptype  uint16
	pad      uint16
	Time_xor uint32
}

func (v *Ucla_req_disp_hdr_t) PackLen() int {
	return 8
}

func (v *Ucla_req_disp_hdr_t) Pack(buf []byte) int {
	index := 0
	binary.BigEndian.PutUint16(buf[index:], v.Apptype)
	index += 4
	binary.BigEndian.PutUint32(buf[index:], v.Time_xor)
	index += 4

	return index
}

func (v *Ucla_req_disp_hdr_t) UnPack(buf []byte) int {
	index := 0
	v.Apptype = binary.BigEndian.Uint16(buf[index:])
	index += 4
	v.Time_xor = binary.BigEndian.Uint32(buf[index:])
	index += 4

	return index
}

//disp 响应数据结构
type Ucla_disp_res_hdr_t struct {
	Errorno   uint32
	Ip        uint32
	Port      uint16
	Global_id uint8
	pad       uint8
}

func (v *Ucla_disp_res_hdr_t) UnPack(buf []byte) int {
	index := 0
	v.Errorno = binary.BigEndian.Uint32(buf[index:])
	index += 4
	v.Ip = binary.BigEndian.Uint32(buf[index:])
	index += 4
	v.Port = binary.BigEndian.Uint16(buf[index:])
	index += 2
	v.Global_id = buf[index]
	index += 2

	return index
}

//udp通讯网络头部
type Ucph_t struct {
	Encrypt bool
	Request bool
	Hlen    uint8
	Ver     uint8

	Flags      uint8
	Request_id uint8
	resve      uint8

	Client_sid uint32
	Device_sid uint32

	Command   uint16
	Param_len uint16
}

func (v *Ucph_t) PackLen() int {
	return UCPH_DHR_SIZE_LEN
}

func (v *Ucph_t) Pack(buf []byte) int {
	index := 0
	var flag byte = 0
	flag |= (v.Ver & 0x07) << 5
	flag |= (v.Hlen & 0x07) << 2
	if v.Request {
		flag |= 0x02
	}
	if v.Encrypt {
		flag |= 0x01
	}
	buf[0] = flag
	buf[1] = v.Flags
	buf[2] = v.Request_id
	index += 4
	binary.BigEndian.PutUint32(buf[index:], v.Client_sid)
	index += 4
	binary.BigEndian.PutUint32(buf[index:], v.Device_sid)
	index += 4
	binary.BigEndian.PutUint16(buf[index:], v.Command)
	index += 2
	binary.BigEndian.PutUint16(buf[index:], v.Param_len)
	index += 2

	return index
}

func (v *Ucph_t) UnPack(buf []byte) int {
	index := 0
	flag := buf[0]
	v.Ver = (flag >> 5) & 0x07
	v.Hlen = (flag >> 2) & 0x07
	if (flag & 0x02) != 0 {
		v.Request = true
	} else {
		v.Request = false
	}
	if (flag & 0x01) != 0 {
		v.Encrypt = true
	} else {
		v.Encrypt = false
	}
	v.Flags = buf[1]
	v.Request_id = buf[2]
	index += 4
	v.Client_sid = binary.BigEndian.Uint32(buf[index:])
	index += 4
	v.Device_sid = binary.BigEndian.Uint32(buf[index:])
	index += 4
	v.Command = binary.BigEndian.Uint16(buf[index:])
	index += 2
	v.Param_len = binary.BigEndian.Uint16(buf[index:])
	index += 2

	return index
}

func Ucla_pkt_new(cmd uint32, param_len uint32, is_request bool, is_enc bool,
	flags uint8, client_sid uint32, device_sid uint32, request_id uint32) *Pkt_t {
	var pkt Pkt_t
	var hdr Ucph_t

	pkt.Total = UCPH_DHR_SIZE_LEN + param_len
	pkt.Cmd = cmd

	hdr.Ver = sdktype.PROTO_VER1
	hdr.Hlen = UCPH_DHR_SIZE_LEN / 4
	hdr.Request = is_request
	hdr.Encrypt = is_enc

	hdr.Flags = flags
	hdr.Client_sid = client_sid
	hdr.Device_sid = device_sid
	hdr.Request_id = uint8(request_id & 0xff)

	hdr.Command = uint16(cmd)
	hdr.Param_len = uint16(param_len)

	pkt.Hlen = UCPH_DHR_SIZE_LEN
	pkt.Data = make([]byte, pkt.Total)
	hdr.Pack(pkt.Data[0:])

	return &pkt
}

//联动认证报文
type Uc_app_user_auth_t struct {
	Action    uint8
	Version   uint8
	Flag      uint8
	resverved uint8
	Random1   [4]uint8
	Username  [sdktype.USER_NAME_LEN]uint8
	Uuid      [sdktype.UUID_LEN]uint8
}

func (v *Uc_app_user_auth_t) Pack(buf []byte) int {
	index := 0
	buf[index] = v.Action
	index += 1
	buf[index] = v.Version
	index += 1
	buf[index] = v.Flag
	index += 2
	copy(buf[index:], v.Random1[0:])
	index += 4
	copy(buf[index:], v.Username[0:])
	index += sdktype.USER_NAME_LEN
	copy(buf[index:], v.Uuid[0:])
	index += sdktype.UUID_LEN

	return index
}

type Uc_app_user_answer_t struct {
	Action    uint8
	resverved [3]uint8
	Random2   [4]uint8
}

func (v *Uc_app_user_answer_t) PackLen() int {
	return 8
}

func (v *Uc_app_user_answer_t) Pack(buf []byte) int {
	index := 0
	buf[0] = v.Action
	buf[1] = v.resverved[0]
	buf[2] = v.resverved[1]
	buf[3] = v.resverved[2]
	index += 4
	copy(buf[index:], v.Random2[0:])
	index += 4

	return index
}

func (v *Uc_app_user_answer_t) UnPack(buf []byte) int {
	index := 0
	v.Action = buf[0]
	v.resverved[0] = buf[1]
	v.resverved[1] = buf[2]
	v.resverved[2] = buf[3]
	index += 4
	copy(v.Random2[0:], buf[index:])
	index += 4

	return index
}

//联动answer 数据结构
type Uc_app_user_question_t struct {
	Action      uint8
	resverved   uint8
	Support_enc uint16
	Md5         [sdktype.UUID_LEN]uint8
}

func (v *Uc_app_user_question_t) PackLen() int {
	return 20
}

func (v *Uc_app_user_question_t) Pack(buf []byte) int {
	index := 0
	buf[index] = v.Action
	index += 2
	binary.BigEndian.PutUint16(buf[index:], v.Support_enc)
	index += 2
	copy(buf[index:], v.Md5[0:])
	index += sdktype.UUID_LEN

	return index
}

func (v *Uc_app_user_question_t) UnPack(buf []byte) int {
	index := 0
	v.Action = buf[index]
	index += 2
	v.Support_enc = binary.BigEndian.Uint16(buf[index:])
	index += 2
	copy(v.Md5[0:], buf[index:])
	index += sdktype.UUID_LEN

	return index
}

//联动result数据结构
type Uc_app_user_result_t struct {
	Action     uint8
	Ver        uint8
	Select_enc uint16
	Err        uint16
	resverved  uint16
}

func (v *Uc_app_user_result_t) PackLen() int {
	return 8
}

func (v *Uc_app_user_result_t) UnPack(buf []byte) int {
	index := 0
	v.Action = buf[index]
	index += 1
	v.Ver = buf[index]
	index += 1
	v.Select_enc = binary.BigEndian.Uint16(buf[index:])
	index += 2
	v.Err = binary.BigEndian.Uint16(buf[index:])
	index += 4

	return index
}
